fix waterfall flow bug and add collectionView always slide

FFIB 6 年之前
父节点
当前提交
804a40e3b4

二进制
PaiAi/Paiai.xcodeproj/project.xcworkspace/xcuserdata/FFIB.xcuserdatad/UserInterfaceState.xcuserstate


+ 12 - 0
PaiAi/Paiai.xcodeproj/xcuserdata/FFIB.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist

@@ -2,4 +2,16 @@
2 2
 <Bucket
3 3
    type = "1"
4 4
    version = "2.0">
5
+   <Breakpoints>
6
+      <BreakpointProxy
7
+         BreakpointExtensionID = "Xcode.Breakpoint.ExceptionBreakpoint">
8
+         <BreakpointContent
9
+            shouldBeEnabled = "Yes"
10
+            ignoreCount = "0"
11
+            continueAfterRunningActions = "No"
12
+            scope = "0"
13
+            stopOnStyle = "0">
14
+         </BreakpointContent>
15
+      </BreakpointProxy>
16
+   </Breakpoints>
5 17
 </Bucket>

+ 0 - 2
PaiAi/PaiaiDataKit/DataLayer/Repositories/Remote/Reusable/NetWork/NetworkApi.swift

@@ -73,7 +73,6 @@ class NetworkApi {
73 73
                         if status == 200 {
74 74
                             observer(.success(data))
75 75
                         } else {
76
-                            print(json)
77 76
                             Toast.show(message: (json["description"]  as? String) ?? "")
78 77
                             observer(.error(BusinessError(id: status)))
79 78
                         }
@@ -95,7 +94,6 @@ class NetworkApi {
95 94
                 .responseJSON { (res) in
96 95
                     switch res.result {
97 96
                     case .success(let json):
98
-                        print(json)
99 97
                         guard let json = json as? [String: AnyObject],
100 98
                             let data = resource.parse(json) else {
101 99
                                 observer(.error(ParseError()))

+ 1 - 1
PaiAi/PaiaiDataKit/DataLayer/Repositories/Remote/WXUserInfoRemoteAPI.swift

@@ -23,7 +23,7 @@ struct WXUserInfoRemoteAPI: UserInfoRemoteAPI {
23 23
         let photoPath =  "https://wx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTJibSYLgvXpMakvD9FaCqfiaWqcMiaiaz905YxWPuO4hy8F2lGheV7kVr9vKKXFgmL1S5s4QJgxwuwtVw/132" //swiftlint:disable:this line_length
24 24
         return Single.create(subscribe: { (observer) in
25 25
             observer(.success(UserInfo(json: ["user_id": "fiDz2Ms" as AnyObject,
26
-                                              "userName": "郑剑飞" as AnyObject,
26
+                                              "nickname": "郑剑飞" as AnyObject,
27 27
                                               "photoPath": photoPath as AnyObject])))
28 28
             return Disposables.create()
29 29
         })

+ 8 - 11
PaiAi/PaiaiDataKit/PresentLayer/Home/HomeViewModel.swift

@@ -39,9 +39,9 @@ public class HomeViewModel {
39 39
         return _hasMoreData.asObservable()
40 40
     }
41 41
 
42
-    public var contents: Observable<[AnimatableSectionModel<Int, PhotoItem>]> {
42
+    public var contents: Observable<[AnimatableSectionModel<String, PhotoItem>]> {
43 43
         return _items.map({ model in
44
-            return [AnimatableSectionModel(model: 0, items: model)]
44
+            return [AnimatableSectionModel(model: "photoItem", items: model)]
45 45
         })
46 46
     }
47 47
 
@@ -88,6 +88,7 @@ public class HomeViewModel {
88 88
                 self._items.accept(self._items.value + result.data)
89 89
                 }, onError: {[weak self] (_) in
90 90
                     guard let `self` = self else { return }
91
+                    self.page -= 1
91 92
                     self._isLoading.onNext(false)
92 93
             }).disposed(by: disposeBag)
93 94
     }
@@ -97,9 +98,13 @@ public class HomeViewModel {
97 98
         let width = item.photo_thumbnail_w
98 99
         let height = item.photo_thumbnail_h
99 100
 
100
-//        header 42, footer: 32
101
+        /// header 42, footer: 32
101 102
         return CGSize(width: width, height: height + 74)
102 103
     }
104
+    
105
+    public func clear() {
106
+        _items.accept([])
107
+    }
103 108
 
104 109
     private func setNotification() {
105 110
         NotificationCenter.default.rx.notification(.GroupItemsChanged).subscribe(onNext: { (notification) in
@@ -138,14 +143,6 @@ public class HomeViewModel {
138 143
 
139 144
 //coordinator delegate
140 145
 extension HomeViewModel {
141
-    public func scanQR() {
142
-        delegate?.scanQR()
143
-    }
144
-
145
-    public func createGroup() {
146
-        delegate?.createGroup()
147
-    }
148
-
149 146
     public func didSelect(_ currIndex: Int) {
150 147
         delegate?.didSelect(_items.value, currIndex: currIndex)
151 148
     }

+ 6 - 0
PaiAi/PaiaiDataKit/PresentLayer/Message/MessageViewModel.swift

@@ -67,4 +67,10 @@ public class MessageViewModel {
67 67
             }
68 68
         }).disposed(by: disposeBag)
69 69
     }
70
+    
71
+    public func clear() {
72
+        sysReadedTip.accept(false)
73
+        thumbupReadedTip.accept(false)
74
+        commentReadedTip.accept(false)
75
+    }
70 76
 }

+ 5 - 2
PaiAi/PaiaiDataKit/PresentLayer/UserInfoViewModel.swift

@@ -18,6 +18,7 @@ public class UserInfoViewModel {
18 18
 
19 19
     public var isLoggedIn: Observable<Void> {
20 20
         return shareUserInfo.asObservable()
21
+            .distinctUntilChanged({ $0.userId == $1.userId })
21 22
             .filter { $0.userId != "" }
22 23
             .flatMapLatest { _ in
23 24
                 return Observable.just(())
@@ -48,8 +49,10 @@ public class UserInfoViewModel {
48 49
                                              guestRemoteAPI: GuestUserInfoRemoteAPI(),
49 50
                                              wxRemoteAPI: WXUserInfoRemoteAPI())
50 51
 
51
-        shareUserInfo.asObservable().subscribe(onNext: { (userInfo) in
52
-            ShareUserId = userInfo.userId
52
+        shareUserInfo.asObservable()
53
+            .distinctUntilChanged({ $0.userId == $1.userId })
54
+            .subscribe(onNext: { (userInfo) in
55
+                ShareUserId = userInfo.userId
53 56
         }).disposed(by: disposeBag)
54 57
 
55 58
         guestLoginBtnTapped.subscribe {[unowned self] _ in

+ 20 - 9
PaiAi/PaiaiUIKit/Reusable/UIKit/WaterfallFlowLayout/WaterfallFlowLayout.swift

@@ -12,10 +12,11 @@ public final class WaterfallFlowLayout: UICollectionViewLayout {
12 12
 
13 13
     private var minColumn: Int = 0
14 14
     private var itemWidth: CGFloat = -1
15
-    private var columnHeights = [CGFloat]()
15
+    private var columnHeights: [CGFloat] = []
16 16
     private var minColumnHeight: CGFloat = 0
17 17
     private(set) var configuration = WaterfallFlowConfiguration()
18
-    private var attributesArr = [UICollectionViewLayoutAttributes]()
18
+    private var attributesArr: [UICollectionViewLayoutAttributes] = []
19
+    private var isNeedLayout: Bool = true
19 20
     override public init() {
20 21
         super.init()
21 22
     }
@@ -24,7 +25,7 @@ public final class WaterfallFlowLayout: UICollectionViewLayout {
24 25
         self.init()
25 26
         self.configuration = configuration
26 27
     }
27
-
28
+    
28 29
     required init?(coder aDecoder: NSCoder) {
29 30
         super.init(coder: aDecoder)
30 31
     }
@@ -39,7 +40,7 @@ public final class WaterfallFlowLayout: UICollectionViewLayout {
39 40
     }
40 41
 
41 42
     override public func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
42
-        guard attributesArr.count <= indexPath.row else {
43
+        guard attributesArr.count <= indexPath.row, isNeedLayout else {
43 44
             return attributesArr[indexPath.row]
44 45
         }
45 46
 
@@ -59,11 +60,10 @@ public final class WaterfallFlowLayout: UICollectionViewLayout {
59 60
 
60 61
     fileprivate func initialize() {
61 62
         guard collectionView?.numberOfSections == 1,
62
-            let itemCount = collectionView?.numberOfItems(inSection: 0),
63
-            itemCount != 0 else { return }
63
+            let itemCount = collectionView?.numberOfItems(inSection: 0) else { return }
64 64
 
65 65
         let originIndex: Int
66
-        if attributesArr.count >= itemCount || itemWidth == -1 {
66
+        if attributesArr.count != itemCount || itemCount == 0 || itemWidth == -1 || isNeedLayout {
67 67
             minColumn = 0
68 68
             originIndex = 0
69 69
             minColumnHeight = 0
@@ -73,6 +73,12 @@ public final class WaterfallFlowLayout: UICollectionViewLayout {
73 73
         } else {
74 74
             originIndex = attributesArr.count
75 75
         }
76
+        
77
+        if itemCount == 0 {
78
+            columnHeights = []
79
+            return
80
+        }
81
+        
76 82
         for i in originIndex..<itemCount {
77 83
             guard let attributes = layoutAttributesForItem(at: IndexPath(row: i, section: 0))
78 84
                 else { continue }
@@ -81,9 +87,9 @@ public final class WaterfallFlowLayout: UICollectionViewLayout {
81 87
     }
82 88
 
83 89
     fileprivate func calculateViewSize() -> CGSize {
84
-        guard let collectionView = collectionView,
90
+        guard let v = collectionView,
85 91
             let maxH = columnHeights.max() else { return CGSize.zero }
86
-        return CGSize(width: collectionView.bounds.width, height: maxH + configuration.rowSpace)
92
+        return CGSize(width: v.bounds.width, height: maxH + configuration.rowSpace)
87 93
     }
88 94
 
89 95
     fileprivate func calculateItemX() -> CGFloat {
@@ -117,4 +123,9 @@ public final class WaterfallFlowLayout: UICollectionViewLayout {
117 123
         columnHeights[minColumn] = minColumnHeight
118 124
         (minColumn, minColumnHeight) = columnHeights.enumerated().min(by: { $0.1 < $1.1 }) ?? (0, 0)
119 125
     }
126
+    
127
+    /// called at collectionView reload
128
+    func setNeedsLayout() {
129
+        isNeedLayout = true
130
+    }
120 131
 }

+ 4 - 5
PaiAi/Paiai_iOS/App/AppCoordinator.swift

@@ -41,9 +41,8 @@ public final class AppCoordinator: BaseCoordinator<Void> {
41 41
 extension AppCoordinator: ContainerViewControllerDelegate {
42 42
     func presentLogin() {
43 43
         let vc = makeLoginViewController()
44
-        coordinate(to: LoginCoordinator(vc,
45
-                                        rootViewController: containerViewController))
46
-            .subscribe(onNext: { (_) in
44
+        coordinate(to: LoginCoordinator(vc))
45
+            .subscribe(onNext: { _ in
47 46
                 vc.removeFromParentAndView()
48 47
             }).disposed(by: disposeBag)
49 48
         navigationController.addFullScreen(childViewController: vc)
@@ -58,7 +57,7 @@ extension AppCoordinator: ContainerViewControllerDelegate {
58 57
     }
59 58
 }
60 59
 
61
-fileprivate extension AppCoordinator {
60
+extension AppCoordinator {
62 61
     func makeContainerViewController() {
63 62
         containerViewController.userInfo = shareUserInfoViewModel
64 63
         containerViewController.delegate = self
@@ -100,7 +99,7 @@ fileprivate extension AppCoordinator {
100 99
     }
101 100
 }
102 101
 
103
-fileprivate extension AppCoordinator {
102
+extension AppCoordinator {
104 103
     func makeMineViewController() -> MineViewController {
105 104
         let vc = MineViewController.instantiate()
106 105
         vc.userInfoViewModel = shareUserInfoViewModel

+ 1 - 0
PaiAi/Paiai_iOS/App/Group/GroupViewController.swift

@@ -63,6 +63,7 @@ final class GroupViewController: UIViewController {
63 63
         collectionView.register(UINib(nibName: "PhotoCell",
64 64
                                       bundle: Bundle(identifier: "com.Paiai-iOS")),
65 65
                                 forCellWithReuseIdentifier: "photoCell")
66
+        collectionView.alwaysBounceVertical = true
66 67
         setup()
67 68
         binding()
68 69
         setupNavigationBar()

+ 10 - 8
PaiAi/Paiai_iOS/App/Home/HomeViewController.swift

@@ -36,7 +36,7 @@ final class HomeViewController: UIViewController {
36 36
         collectionView.register(UINib(nibName: "PhotoCell",
37 37
                                       bundle: Bundle(identifier: "com.Paiai-iOS")),
38 38
                                 forCellWithReuseIdentifier: "photoCell")
39
-        
39
+        collectionView.alwaysBounceVertical = true
40 40
         setup()
41 41
         binding()
42 42
     }
@@ -69,12 +69,12 @@ final class HomeViewController: UIViewController {
69 69
 /// UI bindings
70 70
 fileprivate extension HomeViewController {
71 71
 
72
-    var dataSource: RxCollectionViewSectionedAnimatedDataSource<AnimatableSectionModel<Int, PhotoItem>> {
73
-        return RxCollectionViewSectionedAnimatedDataSource<AnimatableSectionModel<Int, PhotoItem>>(
72
+    var dataSource: RxCollectionViewSectionedAnimatedDataSource<AnimatableSectionModel<String, PhotoItem>> {
73
+        return RxCollectionViewSectionedAnimatedDataSource<AnimatableSectionModel<String, PhotoItem>>(
74 74
             configureCell: {(_, collectionView, indexPath, item) -> UICollectionViewCell in
75
-            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "photoCell",
76
-                                                          for: indexPath) as! PhotoCell
77
-            cell.setInfo(item, source: .home)
75
+                let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "photoCell",
76
+                                                              for: indexPath) as! PhotoCell
77
+                cell.setInfo(item, source: .home)
78 78
             return cell
79 79
         })
80 80
     }
@@ -111,14 +111,16 @@ fileprivate extension HomeViewController {
111 111
     func bindUserInfoViewModelToView() {
112 112
         userInfoViewModel.isLoggedIn
113 113
             .asDriver(onErrorJustReturn: ())
114
-            .drive(onNext: { (_) in
114
+            .drive(onNext: {[unowned self] _ in
115
+                self.viewModel.clear()
115 116
                 self.collectionView.startRefreshing(at: .top)
116 117
             }).disposed(by: disposeBag)
117 118
     }
118 119
 
119 120
     func bindViewModelToCollectionView() {
120 121
         viewModel.contents
121
-            .bind(to: collectionView.rx.items(dataSource: dataSource))
122
+            .asDriver(onErrorDriveWith: .empty())
123
+            .drive(collectionView.rx.items(dataSource: dataSource))
122 124
             .disposed(by: disposeBag)
123 125
     }
124 126
 

+ 5 - 9
PaiAi/Paiai_iOS/App/Login/LoginCoordinator.swift

@@ -10,21 +10,17 @@ import UIKit
10 10
 import RxSwift
11 11
 import PaiaiDataKit
12 12
 
13
-class LoginCoordinator: BaseCoordinator<UserInfo> {
14
-    private let rootViewController: UIViewController
13
+class LoginCoordinator: BaseCoordinator<Void> {
15 14
     private let loginViewController: LoginViewController
16 15
 
17
-    init(_ loginViewController: LoginViewController,
18
-         rootViewController: UIViewController) {
19
-        self.rootViewController = rootViewController
16
+    init(_ loginViewController: LoginViewController) {
20 17
         self.loginViewController = loginViewController
21 18
 
22 19
         super.init(navigationController: UINavigationController(), viewController: loginViewController)
23 20
     }
24 21
 
25
-    override func start() -> Observable<UserInfo> {
26
-        let viewModel = UserInfoViewModel()
27
-        loginViewController.userInfoViewModel = viewModel
28
-        return viewModel.shareUserInfo.asObservable()
22
+    override func start() -> Observable<Void> {
23
+        
24
+        return loginViewController.userInfoViewModel.loginCompleted
29 25
     }
30 26
 }

+ 0 - 7
PaiAi/Paiai_iOS/App/Login/LoginViewController.swift

@@ -39,7 +39,6 @@ extension LoginViewController {
39 39
     func binding() {
40 40
         bindInteraction()
41 41
         bindScrollViewDelegate()
42
-        bindUserInfoViewModelToView()
43 42
     }
44 43
 
45 44
     func bindInteraction() {
@@ -52,12 +51,6 @@ extension LoginViewController {
52 51
             .disposed(by: disposeBag)
53 52
     }
54 53
 
55
-    func bindUserInfoViewModelToView() {
56
-        userInfoViewModel.loginCompleted.subscribe {[unowned self] _ in
57
-            self.removeFromParentAndView()
58
-        }.disposed(by: disposeBag)
59
-    }
60
-
61 54
     func bindScrollViewDelegate() {
62 55
         scrollView.rx.didEndDecelerating
63 56
             .asDriver()

+ 1 - 0
PaiAi/Paiai_iOS/App/Message/MessageViewController.swift

@@ -59,6 +59,7 @@ extension MessageViewController {
59 59
         userInfoViewModel.isLoggedIn
60 60
             .asDriver(onErrorJustReturn: ())
61 61
             .drive(onNext: {[unowned self] (_) in
62
+                self.viewModel.clear()
62 63
                 self.viewModel.reload()
63 64
             }).disposed(by: disposeBag)
64 65
     }

+ 9 - 13
PaiAi/Paiai_iOS/App/Mine/MineCoordinator.swift

@@ -33,10 +33,15 @@ extension MineCoordinator: MineViewControllerDelegate {
33 33
     func logout() {
34 34
         mineViewController.dismissController()
35 35
         didCancel.onNext(())
36
-
37
-        let vc = makeLoginViewController()
38
-        vc.userInfoViewModel = mineViewController.userInfoViewModel
39
-        navigationController.addFullScreen(childViewController: vc)
36
+        
37
+        guard let coordinator = parentCoordinator as? AppCoordinator else { return }
38
+        
39
+        let vc = coordinator.makeLoginViewController()
40
+        let loginCoordinator = LoginCoordinator(vc)
41
+        coordinator.coordinate(to: loginCoordinator).subscribe { _ in
42
+            vc.dismissController()
43
+        }.disposed(by: disposeBag)
44
+        navigationController.presentController(vc)
40 45
     }
41 46
 
42 47
     func didSelect(_ item: MineItem) {
@@ -58,9 +63,6 @@ extension MineCoordinator: MineViewControllerDelegate {
58 63
             self.didCancel.onNext(())
59 64
         }).disposed(by: disposeBag)
60 65
     }
61
-
62
-    func loginout() {
63
-    }
64 66
 }
65 67
 
66 68
 extension MineCoordinator: MineGroupViewModelDelegate {
@@ -74,12 +76,6 @@ extension MineCoordinator: MineGroupViewModelDelegate {
74 76
 }
75 77
 
76 78
 fileprivate extension MineCoordinator {
77
-    func makeLoginViewController() -> LoginViewController {
78
-        let vc = LoginViewController.instantiate()
79
-//        vc.userInfoViewModel = shareUserInfoViewModel
80
-        return vc
81
-    }
82
-
83 79
     func makeMineGroupViewController() -> MineGroupViewController {
84 80
         let vc = MineGroupViewController.instantiate()
85 81
         vc.viewModel = MineGroupViewModel()

+ 2 - 0
PaiAi/Paiai_iOS/Reusable/BaseCoordinator.swift

@@ -20,6 +20,7 @@ public class BaseCoordinator<ResultType> {
20 20
 
21 21
     private let identifier = UUID()
22 22
     private var childCoordinators = [UUID: Any]()
23
+    var parentCoordinator: (Any)? = nil
23 24
 
24 25
     init(navigationController: UINavigationController, viewController: UIViewController) {
25 26
         self.viewController = viewController
@@ -37,6 +38,7 @@ public class BaseCoordinator<ResultType> {
37 38
 
38 39
     func coordinate<T>(to coordinator: BaseCoordinator<T>) -> Observable<T> {
39 40
         store(coordinator: coordinator)
41
+        coordinator.parentCoordinator = self
40 42
         return coordinator.start()
41 43
             .do(onNext: { [weak self] _ in
42 44
                 self?.free(coordinator: coordinator)